package cn.virens.common.mybatis.init;

import cn.virens.common.util.exception.APIException;
import org.dromara.hutool.core.regex.ReUtil;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class InitExecutorFactory {
    private final Map<String, InitExecutorInter> funStack = new ConcurrentHashMap<>();

    protected String format(Map<String, Object> map, String sql) throws APIException {
        // SQL生成:根据key值获取map中的参数,如果不存在，根据fun调用对应的生成器生成----
        sql = ReUtil.replaceAll(sql, "\\{@(\\w+):(\\w+)\\}", m -> {
            return str(map.computeIfAbsent(m.group(2), k -> {
                return call(map, m.group(1));
            }));
        });
        // SQL生成:根据key值获取map中的参数---------------------------------------
        sql = ReUtil.replaceAll(sql, "\\{(\\w+)\\}", m -> {
            return str(map.get(m.group(1)));
        });

        return safe(map, sql);
    }

    /**
     * SQL生成: 剔除忽略表达式中标识符
     *
     * @param map 模版参数
     * @param sql 动态SQL
     * @return
     * @throws APIException
     */
    private String safe(Map<String, Object> map, String sql) throws APIException {
        return ReUtil.replaceAll(sql, "\\{-(\\w+)-\\}", m -> {
            return "{" + str(m.group(1)) + "}";
        });
    }

    /**
     * 生成SQL生成器
     */
    public InitExecutor executor() throws APIException {
        return new InitExecutor(this);
    }

    /**
     * 调用函数对参数进行生成
     *
     * @param map 模版参数
     * @param key 动态变量KEK
     * @return 生成值
     * @throws APIException 一般异常
     */
    private Object call(Map<String, Object> map, String key) throws APIException {
        InitExecutorInter fun = funStack.get(key);

        if (fun != null && map != null) {
            return fun.apply(map);
        } else {
            return "";
        }
    }

    private static String str(Object obj) throws APIException {
        return obj != null ? sql(obj.toString()) : "";
    }

    /**
     * 防止用户发送SQL注入相关词汇
     *
     * @param inputKeyword SQL文本
     * @return 安全SQL
     * @throws APIException 一般异常
     */
    private static String sql(String inputKeyword) throws APIException {
        if (inputKeyword != null && !inputKeyword.isEmpty()) {
            return inputKeyword.replaceAll("([';])+|(--)+", "");
        } else {
            return "";
        }
    }

    /**
     * 添加可用的函数
     *
     * @param fun      函数KEY
     * @param function 函数实现
     */
    public void addFun(String fun, InitExecutorInter function) {
        this.funStack.put(fun, function);
    }

}
